Grundfälle der ebenen Vektoralgebra

Oktober 2020
Keywords: Webkinematik, Webentwicklung, Getriebekinematik, Mechanismentechnik, Bewegungsübertragung, Kraftübertragung, Vektoralgebra, g2, mec2

6.3 Grundfall IV

6.3.1 Aufgabenstellung

Prüfen Sie den vorliegenden Mechanismus auf Freiheitsgrad, Anzahl seiner Maschen und Umlauffähigkeit. Analysieren Sie den Mechanismus anschließend und stellen Sie ihn mit g2 interaktiv im Browser so dar, dass er nur in montierbaren Positionen gerendert wird.

Geg.: a=120\quad a=120, b=200b=200, c=150c=150, d=250d=250, 0°<φ<360°0°<φ<360°

6.3.2 Freiheitsgrad und Maschenzahl

Der Freiheitsgrad nach Grübler lässt sich über folgende Gleichung bestimmen:

F=3(n1)b12b2F=3(n−1)−b_1−2b_2

mit

  • b1=b_1= Anzahl der Gelenke denen 1 Freiheitsgrad entzogen wurde
  • b2=b_2= Anzahl der Gelenke denen 2 Freiheitsgrade entzogen wurden
  • n=n= Anzahl der Glieder

Die Maschenanzahl berechnet sich durch

M=b1+b2n+1M=b_1+b_2−n+1

Für den gegebenen Mechanismus gilt n=4n=4, b1=4b_1=4, b2=0b_2=0 und somit F=1F=1 und M=1M=1. Es handelt sich um ein zwangsläufiges Getriebe mit nur einer Masche.

6.3.3 Umlauffähigkeit:

Die Umlauffähigkeit eines Viergelenks ist definiert durch

lmax+lmin<Restlil_{max}+l_{min}<\sum_{Rest}l_i

beziehungsweise

lmax+lmin=Restlil_{max}+l_{min}=\sum_{Rest}l_i

für durchschlagende Getriebe. Montierbarkeit ist gegeben wenn

lmax<Restlil_{max}<\sum_{Rest}l_i

Für das vorliegende Getriebe gilt

lmax+lmin<Restlid+a<b+c370350l_{max}+l_{min}<\sum_{Rest}l_i\Harr d+a<b+c\Harr370\nless350

Es ist also nicht umlauffähig aber grundsätzlich montierbar, denn

lmax<Restlid<a+b+c250<470l_{max}<\sum_{Rest}l_i \Harr d<a+b+c \Harr 250<470

6.3.4 Analyse:

Aus der Maschengleichung lässt sich Grundfall IV identifizieren

aeφ+beθceψdex=0beθceψ=ga\bm e_\varphi+b\bm e_\theta−c\bm e_\psi−d\bm e_x=\bm 0\Harr b\underline{\bm e_\theta} − c\underline{\bm e_\psi} = \bm g

mit

g=dexaeφ\bm g = d\bm e_x−a\bm e_\varphi

Grundfall IV:

aeαbeβ=ca\bm e_\alpha−b\bm e_\beta=\bm c

Lösung:

eα=λc+μc~aundeβ=aeαcb\bm e_\alpha=\frac{\lambda\bm c +\mu\bm{\tilde c}}{a}\quad und \quad \bm e_\beta = \frac{a\bm e_\alpha - \bm c}{b}

mit

λ=12(a2c2b2c2+1)undμ=±b2c2λ2\lambda= \frac{1}{2}\left(\frac{a^2}{c^2}-\frac{b^2}{c^2}+1\right)\quad und\quad \mu = \pm\sqrt{\frac{b^2}{c^2}-\lambda^2}

Mit getauschten Variablen ergibt sich für unseren Mechanismus

eθ=1b[λ(gxgy)+μ(gygx)]eψ=1c[b(eθxeθy)(gxgy)]\begin{aligned} \bm e_\theta &=\frac{1}{b}\left[\lambda\begin{pmatrix}g_x\\g_y\end{pmatrix}+\mu\begin{pmatrix}-g_y\\g_x\end{pmatrix}\right]\\\\ \bm e_\psi &= \frac{1}{c}\left[b\begin{pmatrix}e_{\theta x}\\e_{\theta y}\end{pmatrix}-\begin{pmatrix}g_x\\g_y\end{pmatrix}\right] \end{aligned}

mit

λ=12(b2c2g2+1)undμ=±b2g2λ2\lambda=\frac{1}{2}\left(\frac{b^2\cdot c^2}{g^2} +1 \right)\quad und\quad \mu=\pm\sqrt{\frac{b^2}{g^2}-\lambda^2}

Quadrieren der Hilfsgeraden gg liefert

g2=a2+d22adcosφ.g^2=a^2+d^2−2ad\cos\varphi.

Es folgen die unbekannten Winkel θ\theta und ψ\psi mit

θ=arctan2[1b(λgy+μgx),1b(λgxμgy)]ψ=arctan2[1c(beθygy),1c(beθxgx)]\begin{aligned} \theta &= \arctan_2\left[\frac{1}{b}(\lambda\cdot g_y +\mu\cdot g_x),\quad\frac{1}{b}(\lambda\cdot g_x - \mu\cdot g_y)\right]\\\\ \psi &= \arctan_2\left[\frac{1}{c}(b\cdot e_{\theta y} - g_y),\quad \frac{1}{c}(b\cdot e_{\theta x}-g_x)\right]\\\\ \end{aligned}

Der Mechanismus ist damit vollständig bestimmt.

6.3.5 Code

Wir erstellen nach bekannten Schema eine neue HTML-Datei (bzw. ändern schlauerweise eine fertige wie z.B. die Kurbel mit 2 Slidern). Wir benötigen unter anderem ein 600x400px Canvas sowie einen Range-Input sowie Output für φ\varphi.

Wir erstellen ein mec-Objekt mit Properties für die Gliedlängen aa, bb, cc, dd und Gettern für eφ\bm e_\varphi, g\bm g, g2g^2, θ\theta, eθ\bm e_\theta, ψ\psi, epsi\bm e_psi sowie den Gelenk- und Gestellpunkten A0A_0, B0B_0, AA, BB.

Das mec-Objekt sieht dann so aus:

mec = { a:120, b:200, c:150, d:250, get ephi() { return { x:Math.cos(phi), y:Math.sin(phi) }; }, get g() { return {x:this.d - this.a*Math.cos(phi), y:- this.a*Math.sin(phi)}; }, get gg() { return this.a*this.a + this.d*this.d - 2*this.a*this.d*Math.cos(phi); }, get theta() { var gg = this.gg, bb_gg = (this.b*this.b)/gg, g = this.g, lambda = 0.5*(bb_gg - this.c*this.c/gg + 1), mue = Math.sqrt(bb_gg - lambda*lambda); return Math.atan2( (1/this.b)*(lambda*g.y + mue*g.x), (1/this.b)*(lambda*g.x - mue*g.y) ) }, get etheta() { return { x:Math.cos(this.theta), y:Math.sin(this.theta)}; }, get psi() { var etheta = this.etheta; return Math.atan2( (1/this.c)*(this.b*etheta.y - this.g.y), (1/this.c)*(this.b*etheta.x - this.g.x) ) }, get epsi() { return { x:Math.cos(this.psi), y:Math.sin(this.psi)}; }, // Gelenkpunkte A0: {x:0, y:0}, get B0() { return {x:this.d, y:0} }, get A() { return {x:this.A0.x + this.a*this.ephi.x, y:this.A0.y + this.a*this.ephi.y}; }, get B() { return {x:this.B0.x + this.c*this.epsi.x, y:this.B0.y + this.c*this.epsi.y}; } }

Nachdem wir world-Objekt

// baut und initialisiert statische Umgebung world = g2().clr() .view({cartesian:true,x:150,y:150}) // Nullpunkt verschoben .use({grp:g}) .nodfix({x:0,y:0}) .nodfix(mec.B0),

und position()-Funktion

function position() { g.del() .beam2({pts:[mec.A0.x, mec.A0.y, mec.A.x, mec.A.y, mec.B.x, mec.B.y, mec.B0.x, mec.B0.y ]}) .nod(mec.A) .nod(mec.B) }

angepasst haben, können wir den Mechanismus im Browser betrachten und stellen fest, dass er in Stellungen gerendert werden kann, die mit der gegebenen Geometrie unmöglich erreicht werden können. Wir müssen also, falls wir den für φ\varphi gegebenen Bereich beibehalten wollen, auf irgendeine Art prüfen ob der Mechanismus bei gerade eingestelltem φ\varphi montierbar ist. Zu diesem Zweck bedienen wir uns der Hilfsgeraden g\bm g, welche die Punkte AA und B0B_0 verbindet. Der Mechanismus muss montierbar sein wenn die Summer der Gliedlängen bb und cc größer ist als die Länge von g\bm g, also Math.sqrt(mec.gg) < (mec.a + mec.b). Diese Bedingung prüfen wir in der Funktion setPhi(), in welcher wir nur dirty auf true setzen und dem Output das Slider-Value zuweisen, wenn das eben genannte zutrifft. Fall die Bedingung false liefert, ändern wir dirty nicht und weisen dem Output einen String zu, der anzeigt, dass der eingestellte Wert für φ\varphi nicht erreichbar ist. Jetzt haben wir noch das Problem, dass hinter dem Output ein ° steht, egal ob vorher eine Zahl oder ein String kommt. Wir packen dieses Grad-Symbol nun in ein Span-Element (Containerelement ohne semantische Bedeutung) mit der Id "grad" und der passenden Abkürzung in den JS Variablen. Dann können wir in setPhi() zusätzlich das Attribut hidden des Span-Elements auf true oder false setzen, je nachdem ob das Grad Zeichen sichtbar sein soll oder nicht. Zusätzlich können wir mittels *ID*.style["color"] = "*FARBE*" noch ein bisschen Styling für den Output betreiben.

Wir erhalten also folgenden Output

<output id="phiout" for="phislider">0</output><span id="grad">°</span>

und ändern setPhi() zu

function setPhi() { if (phislider.value != phiout.value) { phi = phislider.value*pi/180; if (Math.sqrt(mec.gg) < (mec.b + mec.c)) { phiout.innerHTML = phislider.value; phiout.style["color"] = "black"; grad.hidden = false; dirty = true; } else { phiout.style["color"] = "red"; phiout.innerHTML = "unzulaessiger Bereich"; grad.hidden = true; } } }

6.3.6 Ergebnis

Der fertige Quelltext sollte folgendermaßen aussehen:

<!doctype html> <html> <head> <meta charset='utf-8'> <title>Kurbelschwinge</title> </head> <body> <h2>Kurbelschwinge - Grundfall 4</h2> <canvas id="c" width="600" height="400" style="border-width:1px;border-style:solid"></canvas> <br> <label for="phislider">&phi;: <input type="range" id="phislider" style="width:550px;vertical-align:middle;padding:0" min="0" max="360" value="0"> <output id="phiout" for="phislider">0</output><span id="grad">°</span> </label> <script src="https://gitcdn.xyz/repo/goessner/g2/master/src/g2.js"></script> <script> const cnv = document.getElementById('c'), ctx = cnv.getContext('2d'), phislider = document.getElementById('phislider'), phiout = document.getElementById('phiout') grad = document.getElementById('grad'), pi = Math.PI, phi = 0, // Laufvariable mec = { a:120, b:200, c:150, d:250, get ephi() { return { x:Math.cos(phi), y:Math.sin(phi) }; }, get g() { return {x:this.d - this.a*Math.cos(phi), y:- this.a*Math.sin(phi)}; }, get gg() { return this.a*this.a + this.d*this.d - 2*this.a*this.d*Math.cos(phi); }, get theta() { var gg = this.gg, bb_gg = (this.b*this.b)/gg, g = this.g, lambda = 0.5*(bb_gg - this.c*this.c/gg + 1), mue = Math.sqrt(bb_gg - lambda*lambda); return Math.atan2( (1/this.b)*(lambda*g.y + mue*g.x), (1/this.b)*(lambda*g.x - mue*g.y) ) }, get etheta() { return { x:Math.cos(this.theta), y:Math.sin(this.theta)}; }, get psi() { var etheta = this.etheta; return Math.atan2( (1/this.c)*(this.b*etheta.y - this.g.y), (1/this.c)*(this.b*etheta.x - this.g.x) ) }, get epsi() { return { x:Math.cos(this.psi), y:Math.sin(this.psi)}; }, // Gelenkpunkte A0: {x:0, y:0}, get B0() { return {x:this.d, y:0} }, get A() { return {x:this.A0.x + this.a*this.ephi.x, y:this.A0.y + this.a*this.ephi.y}; }, get B() { return {x:this.B0.x + this.c*this.epsi.x, y:this.B0.y + this.c*this.epsi.y}; } }, g = g2(), // baut und initialisiert statische Umgebung world = g2().clr() .view({cartesian:true,x:150, y:150}) // Nullpunkt verschoben .use({grp:g}) .nodfix({x:0,y:0}) .nodfix(mec.B0); let dirty = true; // wenn true gibt es was zu aktualisieren function position() { g.del() .beam2({pts:[mec.A0.x, mec.A0.y, mec.A.x, mec.A.y, mec.B.x, mec.B.y, mec.B0.x, mec.B0.y ]}) .nod(mec.A) .nod(mec.B) } function render() { if (dirty) { position(); // aktualisiere Position world.exe(ctx); // rendert world in den Context dirty = false; } requestAnimationFrame(render); // asynchroner callback von render(), keine Rekursion! } function setPhi() { if (phislider.value != phiout.value) { phi = phislider.value*pi/180; if (Math.sqrt(mec.gg) < (mec.b + mec.c)) { phiout.innerHTML = phislider.value; phiout.style["color"] = "black"; grad.hidden = false; dirty = true; } else { phiout.style["color"] = "red"; phiout.innerHTML = "unzulaessiger Bereich"; grad.hidden = true; } } } /* * Initialisierung */ // Eventlistener hinzufuegen phislider.addEventListener("input",setPhi); // Animation starten render(); </script> </body> </html>